﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Sustainalytics.ClientDW.DataAccessLayer;
using Sustainalytics.ClientDW.Entities.Universes;
using Sustainalytics.DataLayer.PI;
using Sustainalytics.Entities.ESGRatings;
using Sustainalytics.Entities.ProductInvolvement;
using Sustainalytics.Synchronization.Interface;

namespace Sustainalytics.ClientDW.Synchronization.Tests
{
    using Sustainalytics.DataLayer.EsgRatings;

    [TestClass]
    public class ProcessedFilesSyncStepTests
    {
        private static Mock<IEsgInputFileRepository> _mockFileEsgInputRepo;
        private static Mock<IUniversesRepository> _mockIUniverseFileUploadRepo;
        private static ProcessedFilesSyncStep _syncStep;
        private static SyncContext _syncContext;
        private static readonly List<ChangedElement> _changedElements = new List<ChangedElement>();
        private static DateTime _currentDate=new DateTime(2015,4,10);
        private static Guid _usedEsgGuid = new Guid();
        private static Guid _failureGuid=new Guid();
        private static Guid _usedPIGuid = new Guid();
        private static Guid _usedUploadLogGuid = new Guid();

        [TestInitialize]
        public void InitTest()
        {
            var esgFileInputComplete = EsgFileInputCompleteCorrect();
            _mockIUniverseFileUploadRepo = new Mock<IUniversesRepository>();
            _mockIUniverseFileUploadRepo = new Mock<IUniversesRepository>();
            _changedElements.Add(ChangedElement(esgFileInputComplete));
            _changedElements.Add(ChangedElement(CreateUploadLog()));
            _mockFileEsgInputRepo = new Mock<IEsgInputFileRepository>();
            _syncStep = new ProcessedFilesSyncStep(
                _mockFileEsgInputRepo.Object,
                _mockIUniverseFileUploadRepo.Object,
                null);
            _syncContext = new SyncContext(ErrorPolicy.CarryOn)
            {
                Report = new ConcurrentBag<string>(),
                PreviousChanges = _changedElements
            };

        }

        private static EsgInputFileComplete EsgFileInputCompleteCorrect()
        {
            var esgFileInputComplete = new EsgInputFileComplete {FileName = "Valid_Excel.xslsx", Id = _usedEsgGuid};
            return esgFileInputComplete;
        }

        private static UploadLog CreateUploadLog()
        {
            return new UploadLog()
            {
               Id = _usedUploadLogGuid
            };
        }

        private static ChangedElement ChangedElement(EsgInputFileComplete esgFileInputComplete)
        {
            return new ChangedElement()
            {
                AffectedCollection = "EsgInputFile",
                AffectedDB = "ClientPlatform",
                AffectedDocument = esgFileInputComplete,
                AffectedDocumentId = esgFileInputComplete.Id,
                AffectedDocumentType =typeof(EsgInputFileComplete),
                AffectedObjectName = Sustainalytics.Synchronization.Interface.ChangedElement.AFFECTED_INPUT_FILE_NAME_OBJECT,
                Detail = new Dictionary<string, object>()
                {
                    {string.Format("Processed at {0}",_currentDate.ToString("G")),string.Format("Step {0}",typeof(EsgInputFile))}
                }
            };
        }

        private static ChangedElement ChangedElement(UploadLog log)
        {
            return new ChangedElement()
            {
                AffectedObjectName = Sustainalytics.Synchronization.Interface.ChangedElement.AFFECTED_INPUT_FILE_NAME_OBJECT,
                AffectedDocument = log,
                AffectedDocumentType = typeof(UploadLog),
                AffectedDocumentId = log.Id
            };
        }

        [TestMethod]
        public void Start_ForEsgInputFile_Should_MarkFileAsProcessed()
        {
            _syncStep.Start(_syncContext);
            _mockFileEsgInputRepo.Verify(a=>a.MarkFileAsProcessed(_usedEsgGuid));
        }

        [TestMethod]
        public void Start_ForEsgInputFile_Should_MarkFileAsProcessedWrite_And_Write_In_Report()

        {
            var output=_syncStep.Start(_syncContext);
            _mockFileEsgInputRepo.Verify(a=>a.MarkFileAsProcessed(_usedEsgGuid));
            Assert.IsTrue(output.Report.Contains(string.Format("The file {0} was marked as processed",EsgFileInputCompleteCorrect().FileName)));
        }

        [TestMethod]
        public void Start_ForEsgInputFile_Should_WriteOnlyReport_NotInMongo_AnErrorOcurred_During_Sync_Policy_is_CarryOn()
        {
            try
            {
                var prev = _syncContext.PreviousChanges.ToList();
                _syncContext.PreviousChanges = prev;
                prev.Add(new ChangedElement()
                {
                    AffectedDocumentId = _failureGuid,
                    AffectedObjectName =
                        Sustainalytics.Synchronization.Interface.ChangedElement.AFFECTED_SYNC_RESULT_NAME_OBJECT
                });
                var output = _syncStep.Start(_syncContext);
                _mockFileEsgInputRepo.Verify(a => a.MarkFileAsProcessed(It.IsNotNull<Guid>()), Times.Never());
                Assert.IsTrue(
                    output.Report.Contains("An error ocurred during previous sync steps,the input files will not be marked as processed in their collections"));
                Assert.IsTrue(
                    output.Report.Contains(
                        string.Format(
                            "The file {0} was marked as processed but was not updated in the collection {1} that is in the database {2}",
                            EsgFileInputCompleteCorrect().FileName, "EsgInputFile", "ClientPlatform")));
            }
            finally
            {
                _syncContext.PreviousChanges = _changedElements;
            }
        }

        [TestMethod]
        public void Start_ForPIInputFile_Should_UpdateFileHistory()
        {
        
            _syncStep.Start(_syncContext);
            
            _mockFileEsgInputRepo.Verify(a=>a.MarkFileAsProcessed(It.IsNotNull<Guid>()));
        }

        [TestMethod]
        public void Start_ForUniverseInputFile_Should_UpdateUploadLog()
        {
            _syncStep.Start(_syncContext);
            _mockIUniverseFileUploadRepo.Verify(a=>a.UpdateUploadLog(It.Is<UploadLog>(c=>c.Id==_usedUploadLogGuid)));
        }
    }
}
